#!/usr/bin/env python

import math, pygame, prog4Helper, random
pygame.init()
pygame.mixer.init()

screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Geometry Defense")
clock = pygame.time.Clock()

def playSound(sound, soundsOn):
    #If sounds are turned on, play requested sound
    if soundsOn:
        sound.play()
        
def genEnemy(level, sRect, dest):
    side = random.randint(0, 3)
    
    if level == 1 or level == 2 or level == 3 or level == 4:
        if side == 0:
            enemy = prog4Helper.CircleEnemy(20, (random.randint(0, sRect.width), 0), dest, 100, 600)
        elif side == 1:
            enemy = prog4Helper.CircleEnemy(20, (sRect.width, random.randint(0, sRect.height)), dest, 100, 400)
        elif side == 2:
            enemy = prog4Helper.CircleEnemy(20, (random.randint(0, sRect.width), sRect.height), dest, 100, 300)
        elif side == 3:
            enemy = prog4Helper.CircleEnemy(20, (0, random.randint(0, sRect.height)), dest, 100, 200)
            
    return enemy

def celebrate(pl, enG, lblG, bg):
    fanfare = pygame.mixer.Sound("fanfare.ogg")
    
    frameCounter = 0
    congratsLbl = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 50), "CONGRATULATIONS!!", (80, 80, 255), (150, 250))
    
    playSound(fanfare, True)
    
    celebrating = True
    while celebrating:
        clock.tick(30)
        
        #counting 0-99
        frameCounter += 1
        frameCounter = frameCounter % 100
        
        #Event handling
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                celebrating = False

            elif event.type == pygame.KEYDOWN:
                #Escape Key - Exit to intro
                if event.key == pygame.K_ESCAPE:
                    celebrating = False
                    
                #Enter Key - Exit to intro
                if event.key == pygame.K_RETURN:
                    celebrating = False

        screen.blit(bg, (0, 0))
        enG.draw(screen)
        lblG.draw(screen)
        pl.draw(screen)
        
        if frameCounter < 50:
            congratsLbl.draw(screen)

        pygame.display.flip()

def paused(lblG):
    background = pygame.Surface(screen.get_size())
    background.fill((0, 0, 0))
    background = background.convert()
    
    pausedLbl = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 20), "GAME PAUSED", (153, 0, 0), (350, 290))
    
    status = True
    stillPaused = True
    while stillPaused:
        clock.tick(30)
        
        #Event handling
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                stillPaused = False
                status = False

            elif event.type == pygame.KEYDOWN:
                #Escape Key - Exit game
                if event.key == pygame.K_ESCAPE:
                    stillPaused = False
                    status = False

                #Space Bar - Pause/Unpause game
                elif event.key == pygame.K_SPACE:
                    stillPaused = False
                    status = True
        
        lblG.update()
        pausedLbl.update()
        
        screen.blit(background, (0, 0))
        lblG.draw(screen)
        pausedLbl.draw(screen)
        
        pygame.display.flip()
        
    return status
        
def game():
    #Set up screen
    scrRect = screen.get_rect()

    #Set up background
    #background = pygame.image.load("bg.gif")
    background = pygame.Surface(screen.get_size())
    background.fill((51, 255, 51))
    background = background.convert()
    
    #Set up sounds
    soundsActive = True
    #bgMusic = pygame.mixer.Sound("bgMusic.ogg") #background music
    deathSound = pygame.mixer.Sound("death.ogg") #player death
    destroySound = pygame.mixer.Sound("destroy.ogg") #enemy destroyed
    levelCompleteSound = pygame.mixer.Sound("levelComplete.ogg") #level complete
    shootSound = pygame.mixer.Sound("shoot.ogg") #shot fired
    
    #Game variables
    ktl = (0, 20, 40, 60, 80, 1)
    currentLvl = 1
    killsToLevel = ktl[currentLvl]
    score = 0
    lives = 3
    frameCounter = 0
    
    #Set up labels for displaying info to user
    scoreLbl = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 20), "SCORE: %d" %score, (153, 0, 0), (10, 550))
    livesLbl = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 20), "LIVES: %d" %lives, (153, 0, 0), (650, 550))
    levelLbl = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 20), "LEVEL: %d" %currentLvl, (153, 0, 0), (650, 10))
    
    #Set up sprite groups
    bulletGroup = pygame.sprite.Group()
    enemyGroup = pygame.sprite.Group()
    labelGroup = pygame.sprite.Group(scoreLbl, livesLbl, levelLbl)
    
    stillAlive = True
    while stillAlive:
        player = prog4Helper.Player((scrRect.width/2, scrRect.height/2))
        bulletGroup.empty()
        enemyGroup.empty()
        frameCounter = 0
        
        canFire = True
        playing = True
        while playing:
            #30 fps
            clock.tick(30)
            
            #Enemy spawning
            #counting 0-99
            frameCounter += 1
            frameCounter = frameCounter % 100
            
            if currentLvl == 1:
                if frameCounter % 48 == 0:
                    enemyGroup.add(genEnemy(currentLvl, scrRect, player.rect.center))
            elif currentLvl == 2:
                if frameCounter % 33 == 0:
                    enemyGroup.add(genEnemy(currentLvl, scrRect, player.rect.center))
            elif currentLvl == 3:
                if frameCounter % 24 == 0:
                    enemyGroup.add(genEnemy(currentLvl, scrRect, player.rect.center))
            elif currentLvl == 4:
                if frameCounter % 14 == 0:
                    enemyGroup.add(genEnemy(currentLvl, scrRect, player.rect.center))
                    
            #Allow player to fire (at appropriate intervals)
            if frameCounter % 10 == 0:
                canFire = True

            #Event handling
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    stillAlive = False
                    playing = False

                elif event.type == pygame.KEYDOWN:
                    #Escape Key - Exit game
                    if event.key == pygame.K_ESCAPE:
                        stillAlive = False
                        playing = False

                    #Space Bar - Pause/Unpause game
                    elif event.key == pygame.K_SPACE:
                        if not paused(labelGroup):
                            stillAlive = False
                            playing = False
                            
                    #S Key - Toggle sounds on/off
                    elif event.key == pygame.K_s:
                        soundsActive = not soundsActive
                    
                    #Ctrl+Alt+X - Skip to next level
                    elif event.key == pygame.K_x:
                        mods = pygame.key.get_mods()
                        if mods & pygame.KMOD_LCTRL and mods & pygame.KMOD_LALT:
                            killsToLevel = 0

                elif event.type == pygame.MOUSEBUTTONDOWN:
                    #Left Mouse Button Down - Fire turret
                    if event.button == 1:
                        if canFire:
                            playSound(shootSound, soundsActive)
                            bulletGroup.add(prog4Helper.Bullet(player.rect.center, player.dir, pygame.mouse.get_pos()))
                            canFire = False

                elif event.type == pygame.MOUSEMOTION:
                    #Update turret facing direction
                    (mx, my) = pygame.mouse.get_pos()
                    my = scrRect.height - my
                    dirInR = math.atan2(my-player.rect.centery, mx-player.rect.centerx)
                    dirInA = dirInR * 180 / math.pi
                    player.updateDir(dirInA, True)
                
            #Update entity locations
            scoreLbl.setText("SCORE: %d" %score)
            livesLbl.setText("LIVES: %d" %lives)
            levelLbl.setText("LEVEL: %d" %currentLvl)
            
            enemyGroup.update(player, bulletGroup)
            bulletGroup.update()
            labelGroup.update()
            player.update()

            #Handle collisions
            #Enemy - Player collision
            if pygame.sprite.spritecollideany(player, enemyGroup) != None:
                #1 Player Death
                playSound(deathSound, soundsActive)
                lives -= 1
                score -= 1
                playing = False

            #Screen - Bullet collision
            for bullet in bulletGroup:
                if bullet.rect.top < 0 or bullet.rect.left < 0 or bullet.rect.right > scrRect.width or bullet.rect.bottom > scrRect.height:
                    bulletGroup.remove(bullet)

            #Enemy - Bullet collision
            #pygame.sprite.groupcollide(enemyGroup, bulletGroup, True, True)
            for bullet in bulletGroup:
                collided = pygame.sprite.spritecollide(bullet, enemyGroup, False)
                
                if collided:
                    for dEnemy in collided:
                        playSound(destroySound, soundsActive)
                        score += dEnemy.points
                        killsToLevel -= 1
                        enemyGroup.remove(dEnemy)

                    bulletGroup.remove(bullet)
                    
            #level completed
            if killsToLevel <= 0:
                playing = False

            #Refresh display
            screen.blit(background, (0, 0))
            bulletGroup.draw(screen)
            enemyGroup.draw(screen)
            labelGroup.draw(screen)
            player.draw(screen)

            pygame.display.flip()
            
        if lives <= 0:
            stillAlive = False
            
        if killsToLevel <= 0:
            playSound(levelCompleteSound, soundsActive)
            killsToLevel = ktl[currentLvl]
            currentLvl += 1
            
            if currentLvl == 5:
                stillAlive = False
                celebrate(player, enemyGroup, labelGroup, background)
        
    return score
        
def intro(score=0):
    #Set up screen
    scrRect = screen.get_rect()
    
    #Set up background
    background = pygame.Surface(screen.get_size())
    background.fill((0, 0, 0))
    
    #Set up previous game's final score (if there is a previous game)
    if score != 0:
        final1 = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 50), "Final Score", (220, 220, 0))
        final2 = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 50), "%d" %score, (220, 220, 0))
        
    #Set up instructions
    inst1 = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 20), "PRESS [ENTER] TO BEGIN A GAME", (153, 0, 0), (100, 20))
    inst2 = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 20), "PRESS [ESC] TO EXIT THE GAME", (153, 0, 0), (100, 40))
    keys1 = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 20), "[s] TOGGLE SOUND EFFECTS ON/OFF", (153, 0, 0), (20, 320))
    keys2 = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 20), "[SPACE] PAUSE/UNPAUSE GAME", (153, 0, 0), (20, 340))
    keys3 = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 20), "MOVE MOUSE TO CHANGE TURRET'S AIMING DIRECTION", (153, 0, 0), (20, 400))
    keys4 = prog4Helper.Label(pygame.font.SysFont("Comic Sans MS", 20), "[LEFT MOUSE BUTTON]  FIRE", (153, 0, 0), (20, 420))
    
    quitGame = False
    keepGoing = True
    while keepGoing:
        #30 fps
        clock.tick(30)
        #Handle events
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                keepGoing = False
                quitGame = True
                
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    keepGoing = False
                    quitGame = True

                elif event.key == pygame.K_RETURN:
                    keepGoing = False
                    quitGame = False
                    
        #Refresh display
        screen.blit(background, (0, 0))
        screen.blit(inst1.image, inst1.rect)
        screen.blit(inst2.image, inst2.rect)
        screen.blit(keys1.image, keys1.rect)
        screen.blit(keys2.image, keys2.rect)
        screen.blit(keys3.image, keys3.rect)
        screen.blit(keys4.image, keys4.rect)

        if score != 0:
            final1.rect.centerx = scrRect.centerx
            final1.rect.top = 160
            final2.rect.centerx = scrRect.centerx
            final2.rect.top = 210
            screen.blit(final1.image, final1.rect)
            screen.blit(final2.image, final2.rect)
            
        pygame.display.update()
        
    return quitGame
        
def main():
    leavingGame = False
    finalScore = 0

    leavingGame = intro()

    while not leavingGame:
        if not leavingGame:
            finalScore = game()

        leavingGame = intro(finalScore)

    pygame.quit()

if __name__ == "__main__":
    main()